#include <stdio.h>
#include <iostream>
#include <memory>
#include <string>
// #include <cassert>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

using namespace std;

class TestClass
{
public:
    TestClass(std::string name) : m_name(name){};
    ~TestClass() = default;

public:
    void setName(std::string name)
    {
        m_name = name;
    }
    std::string getName()
    {
        return m_name;
    }
    void showName()
    {
        printf("ClassPrint:[%p] Name:[%s]\n", this, m_name.c_str());
    };

private:
    std::string m_name;
};

// 据说可以处理循环引用问题
void weak_ptr_test()
{

    long shared_p1_count = 0;
    long shared_p2_count = 0;
    long shared_p3_count = 0;
    long weak_p1_count = 0;
    long weak_p2_count = 0;

    TestClass *p_test1 = new TestClass("weak_ptr test1");

    std::shared_ptr<TestClass> shared_p1(p_test1);
    shared_p1_count = shared_p1.use_count();
    assert(shared_p1_count == 1); //断言：shared_p1 引用计数1

    std::shared_ptr<TestClass> shared_p2(shared_p1);
    shared_p1_count = shared_p1.use_count();
    shared_p2_count = shared_p2.use_count();
    assert(shared_p1_count == 2); //断言：shared_p1 引用计数2
    assert(shared_p2_count == 2); //断言：shared_p2 引用计数2

    // weak_ptr不能由指针直接构建
    std::weak_ptr<TestClass> weak_p1(shared_p1);
    shared_p1_count = shared_p1.use_count();
    shared_p2_count = shared_p2.use_count();
    weak_p1_count = weak_p1.use_count();
    assert(shared_p1_count == 2); // 断言： shared_p1 引用计数2
    assert(shared_p2_count == 2); // 断言： shared_p2 引用计数2
    assert(weak_p1_count == 2);   // 断言： shared_p2 引用计数2

    std::weak_ptr<TestClass> weak_p2 = weak_p1;
    shared_p1_count = shared_p1.use_count();
    shared_p2_count = shared_p2.use_count();
    weak_p1_count = weak_p1.use_count();
    weak_p2_count = weak_p2.use_count();
    assert(shared_p1_count == 2); // 断言： shared_p1 引用计数2
    assert(shared_p2_count == 2); // 断言： shared_p2 引用计数2
    assert(weak_p1_count == 2);   // 断言： weak_p1 引用计数2
    assert(weak_p1_count == 2);   // 断言： weak_p1 引用计数2

    // weak_p1->showName();                            //Error! 编译器出错！weak_ptr没有重载* 和 -> ，无法直接当指针用

    std::shared_ptr<TestClass> shared_p3 = weak_p2.lock(); //OK!可以通过weak_ptr的lock方法获得shared_ptr
    shared_p1_count = shared_p1.use_count();
    shared_p2_count = shared_p2.use_count();
    shared_p3_count = shared_p3.use_count();
    weak_p1_count = weak_p1.use_count();
    weak_p2_count = weak_p2.use_count();
    assert(shared_p1_count == 3); // 断言： shared_p1 引用计数3
    assert(shared_p2_count == 3); // 断言： shared_p2 引用计数3
    assert(shared_p3_count == 3); // 断言： shared_p3 引用计数3
    assert(weak_p1_count == 3);   // 断言： weak_p1 引用计数3
    assert(weak_p1_count == 3);   // 断言： weak_p1 引用计数3

    shared_p3->showName(); // 转为shared_ptr使用指针

    shared_p1 = nullptr;
    shared_p2 = nullptr;
    shared_p3 = nullptr;

    shared_p1_count = shared_p1.use_count();
    shared_p2_count = shared_p2.use_count();
    shared_p3_count = shared_p3.use_count();
    weak_p1_count = weak_p1.use_count();
    weak_p2_count = weak_p2.use_count();
    assert(shared_p1_count == 0); // 断言： shared_p1 引用计数3
    assert(shared_p2_count == 0); // 断言： shared_p2 引用计数3
    assert(shared_p3_count == 0); // 断言： shared_p3 引用计数3
    assert(weak_p1_count == 0);   // 断言： weak_p1 引用计数3
    assert(weak_p1_count == 0);   // 断言： weak_p1 引用计数3

    std::shared_ptr<TestClass> shared_p4 = weak_p2.lock();
    // shared_p4->showName();// ERROR: 指针已经释放

    bool weak_p2_expired = weak_p2.expired();
    assert(weak_p2_expired); // 断言： weak_p2 已过期
}

// shared_ptr需要注意循环引用导致的内存泄露
void shared_ptr_test()
{
    TestClass *p_test1 = new TestClass("test1 shared_ptr");
    TestClass *p_test2 = new TestClass("test2 shared_ptr");

    std::shared_ptr<TestClass> p1(p_test1);
    std::shared_ptr<TestClass> p2(p_test2);
    std::shared_ptr<TestClass> p3(p2);

    p1->showName();
    p2->showName();
    p3->showName();
    std::cout << p1.use_count() << ":" << p2.use_count() << ":" << p3.use_count() << std::endl;

    assert(p1.get() == p_test1);
    assert(p2.get() == p_test2);
    assert(p3.get() == p_test2);
    assert(p1.use_count() == 1);
    assert(p2.use_count() == 2);
    assert(p3.use_count() == 2);

    // p2.reset(p1.get());// 错误，危险写法，这样写p2不知道p1的存在，这样写有潜在的危险，导致p2与p1释放时都释放同一个指针

    p2 = p1;
    p1->showName();
    p2->showName();
    p3->showName();
    std::cout << p1.use_count() << ":" << p2.use_count() << ":" << p3.use_count() << std::endl;

    assert(p1.get() == p_test1);
    assert(p2.get() == p_test1);
    assert(p3.get() == p_test2);
    assert(p1.use_count() == 2);
    assert(p2.use_count() == 2);
    assert(p3.use_count() == 1);

    p1 = nullptr; //p1.reset();
    assert(p1 == nullptr);
    assert(p2.unique());
    assert(p3.unique());
    p2->showName();
    p3->showName();
    std::cout << p2.use_count() << ":" << p3.use_count() << std::endl;

    p_test1->showName();
    p_test2->showName();
    p2.reset();          //p2 = nullptr;//p_test1指针被销毁
    p3.reset();          //p_test2指针被销毁
    p_test1->showName(); // 错误，指针被销毁
    p_test2->showName();
}

/**
 * @brief 过时了，跟不上时代了，还没用就过时了。。。。
 * 
 */
void auto_ptr_test()
{
    //忽略 用unique_ptr代替
}

/**
 * @brief unique_ptr 独享智能指针 测试
 * 
 * 
 */
void unique_ptr_test()
{
    TestClass *test_ptr = new TestClass("test1");

    std::unique_ptr<TestClass> p1(test_ptr);

    printf("使用指针\n");
    p1->showName();

    printf("修改指针指向的内容\n");
    p1->setName("test1 unique_ptr");
    p1->showName();

    printf("指针与智能指针脱离关系\n");
    TestClass *temp = p1.release(); // release() 脱离关系，指针未销毁
    temp->showName();
    if (p1 == nullptr)
    {
        std::cout << "p1 is nullptr" << std::endl;
    }
    printf("指针与智能指针绑定关系\n");
    p1.reset(temp);
    p1->showName();
    temp->showName();

    printf("重设指针\n");
    p1.reset(); //指针会倍释放
    if (p1 == nullptr)
    {
        std::cout << "p1 is nullptr" << std::endl;
    }
    // temp->showName(); //错误 指针执行的空间已被释放

    std::unique_ptr<TestClass> p2(new TestClass("test2 unique_ptr"));
    p2->showName();
    printf("转移指针\n");
    p1 = std::move(p2);
    if (p2 == nullptr)
    {
        std::cout << "p2 is nullptr" << std::endl;
    }
    p1->showName();
    // p2->showName();//错误 指针已经转移到p1
}

void shared_ptr_memory_free_test()
{
    char *target = (char *)malloc(5);
    memset(target, 0, 5);
    target[0] = 't';
    target[1] = 'e';
    target[2] = 's';
    target[3] = 't';
    printf("%s\n", target);

    {
        std::shared_ptr<char> pChar(target);
        printf("%s\n", pChar);
    }
    printf("Hello World!\n");
}

/**
 * @brief 智能指针测试
 * 
 * @param argn 
 * @param argv 
 * @return int 
 */
int main(int argn, char **argv)
{
    // unique_ptr_test();
    // shared_ptr_test();
    // weak_ptr_test();

    /**
     * @brief shared_ptr 内存释放测试
     * 
     */
    shared_ptr_memory_free_test();
}